from datetime import datetime

from flask import Blueprint, request
from flask import jsonify
from sqlalchemy.exc import SQLAlchemyError

from db.controller.db_controller import db_controller
from enums.modbus_funcode import ModbusFunctionCode
from enums.modbus_register import RegisterType
from web.log import log
from web.model.slave import Slave, SlaveIdList, SlaveAddress, SlaveInfo, WriteRegister
from service.client_manager import client_manager

# 创建蓝图对象
slave_blueprint = Blueprint('slave', __name__)


@slave_blueprint.route('/slave/add_slave', methods=['POST'])
def add_slave():
    body = Slave(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    try:
        if db_controller.slave_dao.add_slave(device_name, slave_id):
            return jsonify({'status': 200, 'msg': '添加从机成功', 'data': True})
        else:
            return jsonify({'status': 500, 'msg': '添加从机失败', 'data': False})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'数据库错误: {e}', 'data': False})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误: {e}', 'data': False})


@slave_blueprint.route('/slave/delete_slave', methods=['POST'])
def delete_slave():
    body = Slave(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    try:
        if db_controller.slave_dao.delete_slave(device_name, slave_id):
            return jsonify({'status': 200, 'msg': '删除从机寄存器地址成功', 'data': True})
        else:
            return jsonify({'status': 500, 'msg': '删除从机寄存器地址失败', 'data': False})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'数据库错误: {e}', 'data': False})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误: {e}', 'data': False})


@slave_blueprint.route('/slave/get_slave_id_list', methods=['POST'])
def get_slave_id_list():
    device_name = SlaveIdList(**request.get_json()).device_name
    try:
        result = db_controller.slave_dao.get_slave_id_list(device_name)
        return jsonify({'status': 200, 'msg': '获取从机ID列表成功', 'data': result})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'数据库错误: {e}', 'data': []})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误: {e}', 'data': []})


@slave_blueprint.route('/slave/set_slave_address', methods=['POST'])
def set_slave_address():
    body = SlaveAddress(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    register_type = body.register_type
    start_address = body.start_address
    end_address = body.end_address
    try:
        if db_controller.slave_dao.set_slave_address(device_name, slave_id, register_type, start_address, end_address):
            return jsonify({'status': 200, 'msg': '设置从机寄存器地址成功', 'data': True})
        else:
            return jsonify({'status': 500, 'msg': '设置从机寄存器地址失败', 'data': False})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'数据库错误 {e}', 'data': False})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误 {e}', 'data': False})


@slave_blueprint.route('/slave/get_slave_table', methods=['POST'])
def get_slave_table():
    body = SlaveInfo(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    register_type = body.register_type
    try:
        device = db_controller.device_dao.is_device_exist(device_name)
        if device is None:
            return jsonify({'status': 200, 'msg': f'无法找到该设备:{device_name}!', 'data': []})
        start_address, end_address = db_controller.slave_dao.get_slave_address(device_name, slave_id, register_type)
        if start_address == -1 or end_address == -1:
            return jsonify({'status': 200, 'msg': f'寄存器地址未设置!', 'data': []})

        result = []
        for address in range(start_address, end_address + 1):
            result.append(address)
        return jsonify({'status': 200, 'msg': '获取从机表数据成功', 'data': result})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'数据库错误 {e}', 'data': []})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误 {e}', 'data': []})


@slave_blueprint.route('/slave/read_register', methods=['POST'])
def read_register():
    body = SlaveAddress(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    register_type = body.register_type
    start_address = body.start_address
    end_address = body.end_address
    try:
        client = client_manager.get_client(device_name)
        if client is None:
            return jsonify({'status': 500, 'msg': f'无法找到该设备:{device_name}!', 'data': []})
        result = []
        value_list = client.read_register(slave_id, register_type, start_address, end_address)
        if value_list is None:
            for index, address in enumerate(range(start_address, end_address + 1)):
                result.append(
                    {'address': address, 'value': 0, "time": datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3],
                     'status': False})
        else:
            for index, address in enumerate(range(start_address, end_address + 1)):
                result.append({'address': address, 'value': value_list[index],
                               "time": datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3], 'status': True})
        return jsonify({'status': 200, 'msg': '读取寄存器成功', 'data': result})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': f'读取寄存器失败, 数据库错误: {e}', 'data': []})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': f'服务器内部错误: {e}', 'data': []})


@slave_blueprint.route('/slave/write_register', methods=['POST'])
def write_register():
    body = WriteRegister(**request.get_json())

    device_name = body.device_name
    slave_id = body.slave_id
    register_type = body.register_type
    start_address = body.start_address
    data_type = body.data_type
    value_list = body.value_list
    write_func = body.write_func
    try:
        client = client_manager.get_client(device_name)

        is_success = False
        if register_type == RegisterType.COIL:
            if write_func == ModbusFunctionCode.WRITE_COIL_REGISTERS:
                is_success = client.write_single_coil_register(slave_id=slave_id, start_address=start_address,
                                                               value_list=value_list)
            else:
                is_success = client.write_coil_registers(slave_id=slave_id, start_address=start_address,
                                                         value_list=value_list)
        elif register_type == RegisterType.HOLDING_REGISTER:
            if write_func == ModbusFunctionCode.WRITE_HOLDING_REGISTERS:
                is_success = client.write_single_holding_register(slave_id=slave_id, start_address=start_address,
                                                                  data_type=data_type, value_list=value_list)
            else:
                is_success = client.write_holding_registers(slave_id=slave_id, start_address=start_address,
                                                            data_type=data_type, values=value_list)
        if is_success:
            return jsonify({'status': 200, 'msg': '写入寄存器成功!', 'data': is_success})
        else:
            return jsonify({'status': 500, 'msg': '写入寄存器失败!', 'data': is_success})
    except SQLAlchemyError as e:
        log.error(f"数据库操作失败: {e}")
        return jsonify({'status': 500, 'msg': '写入寄存器失败, 数据库错误', 'data': False})
    except Exception as e:
        log.error(f"未知错误: {e}")
        return jsonify({'status': 500, 'msg': '写入寄存器失败, 服务器内部错误', 'data': False})
